<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        html,body{
            width: 100%;
            height: 100%;
        }
        #test{
            width: 100%;
            height: 100%;
            position: relative;
        }
        p{
            width: 50px;
            height: 50px;
            background-color: pink;
            position: absolute;
            left: 0;
            top: 0;
        }
    </style>
</head>

<body>
    <!-- <input type="text" id="search" > -->

    <div id="test">
        <p id="box"></p>
    </div>
</body>

</html>
<script>
    // 利用字面量定义一个对象
    // var obj = {
    //     username: '小黄',
    //     age: 18,
    //     family: {
    //         username: '妈妈',
    //         family1: {
    //             username: '奶奶',
    //         }
    //     }
    // }
    //var user = fun(obj)//在js中不止变量具有提升，函数也是具有提升的
    //var user=obj  //将对象赋值给一个普通变量的形式就是对对象的浅拷贝类似于重命名不改变内容，栈中多了一份地址但是，堆里面的数据还是同一份数据
    //obj.username = '小红'  //找到对象里的属性名改变对象里的属性值‘小黄’--改成‘小红’此时对象里的username属性的值已经发生改变
    //obj.family.username = '爸爸'  //当改变对象里的子对象的属性值时深拷贝就有点力不从心了，你会发现它改变了子对象的属性值也就是当对象里的属性值是引用数据类型时，由于引用数据类型的数据是存在堆中，它只拷贝了一层，这时候就需要用到递归了
    //console.log(user)   //控制台打印这个变量

    //利用函数封装实现对obj这个对象的深拷贝，拷贝一份新的对象后再改变原对象的属性值就不会对新拷贝的对象产生影响了
    //function fun(obj = {}) {
        //判断obj是否为对象或者null,如果不是直接把传过来的这个形参obj给return出去
        // if (typeof obj != "object" || obj == null) {
        //     return obj
        // }
        // 定义一个变量来存储我要复制的结果
        // let result;
        // if (obj instanceof Array) {  //如果obj这个形参的数据类型是个数组的h话就让result这个变量是一个【】的数组
        //     result = []
        // } else {    //否则result是一个对象
        //     result = {}
        // }
        //遍历对象
        // for (var i in obj) {
            // 判断对象里的属性是否是自身属性
            // if (obj.hasOwnProperty(i)) {
                // 简单理解递归就是函数自己调用自己的方式我们称之为递归
                // 相当于在赋值的过程中，如果obj里面还嵌套了子对象的话会再调用一次函数拷贝一下子对象里的属性，它会一直拷贝下去
                // result[i] = fun(obj[i])
            // }
        // }
        // return result;
    // }
    // function test(num){
    //     //判断特殊  0 或者1
    //     if(num==0||num==1){
    //         return 1
    //     }
    //     var sum=1
    //     sum=num*test(num-1)
    //     return sum
    // }
    // console.log(test(5))  //   1*2*3*4*5   ||   5*4*3*2*1    ---结果都是120

    //闭包
    // function test(){
    //     var a=123
    //     var fun=function(){
    //         console.log(a)  //找到它的外层test这个函数作用域里面的局部变量输出在控制台
    //     }
    //     fun()  //调用test内部的这个函数
    // }
    // test()  //调用test这个函数


    // function test(){
    //     var a=123
    //    function fn(){ // return 返回出去一个函数
    //         console.log(a)  //找到它的外层test这个函数作用域里面的局部变量输出在控制台
    //     }
    //     fn()
    // }
    // test()  //调用test这个函数

    /* 应用场景：窗口操作后者输入框输入时，我们不希望频繁的触发事件处理函数，这样会家中浏览器和服务器的负担，比如输入框每次按键的按下抬起都会触发事件处理函数太频繁了，这个时候我们就可以使用防抖和节流来实现效果的同时又减少了事件处理函数的触发频率减轻了浏览器负担 */



    /* --------------------------------------------------------------------- */
    //防抖函数  callback  回调  时长 delay
    // 防抖总结：一点时间断内只触发一次函数，原理是通过判断是否到达一定时间来触发函数
    // function fun(callback,delay){
    //     //声明一个定时器变量
    //     var timer=null
    //     return function(){  //return返回的是个函数，在函数内部先清楚了定时器又设置了定时器
    //         //清除定时器
    //         clearTimeout(timer)
    //         //给这个定时器变量设置值
    //         timer=setTimeout(callback,delay)
    //     }
    // }

    // var obj=document.querySelector('#search')
    // obj.oninput=function(){
    //     console.log(this.value)
    // }
    // obj.oninput=fun(()=>{
    //     console.log('到最后的时候才触发')
    // },500)

    /* ------------------------------------------------------- */
    //节流函数
    function fun(callback,delay){
        // console.log(222)
        //定义一个最后的时间
        var last=null
        return function(){
            // console.log(111)
            //获取现在的时间戳
            var start=new Date().getTime()
            // console.log(start)

            if(start-last>=delay){
                callback()
                //将当前的时间作为最后时间
                last=start
            }
        }
    }
    // fun()()
    document.querySelector('#test').onmousemove=fun(()=>{
        var obj=document.querySelector('#box')
        obj.style.left=event.clientX+'px'
        obj.style.top=event.clientY+'px'
    },50)
</script>